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

use geom::matrix::{Matrix4, identity};
use geom::size::Size2D;
use geom::rect::Rect;
use opengles::gl2::{GLuint, delete_textures};
use std::managed::mut_ptr_eq;

pub enum Format {
    ARGB32Format,
    RGB24Format
}

pub enum Layer {
    ContainerLayerKind(@mut ContainerLayer),
    TextureLayerKind(@mut TextureLayer),
    ImageLayerKind(@mut ImageLayer),
    TiledImageLayerKind(@mut TiledImageLayer)
}

impl Layer {
    pub fn with_common<T>(&self, f: &fn(&mut CommonLayer) -> T) -> T {
        match *self {
            ContainerLayerKind(container_layer) => f(&mut container_layer.common),
            TextureLayerKind(texture_layer) => f(&mut texture_layer.common),
            ImageLayerKind(image_layer) => f(&mut image_layer.common),
            TiledImageLayerKind(tiled_image_layer) => f(&mut tiled_image_layer.common)
        }
    }
}

pub struct CommonLayer {
    parent: Option<Layer>,
    prev_sibling: Option<Layer>,
    next_sibling: Option<Layer>,

    transform: Matrix4<f32>,
}

impl CommonLayer {
    // FIXME: Workaround for cross-crate bug regarding mutability of class fields
    pub fn set_transform(&mut self, new_transform: Matrix4<f32>) {
        self.transform = new_transform;
    }
}

pub fn CommonLayer() -> CommonLayer {
    CommonLayer {
        parent: None,
        prev_sibling: None,
        next_sibling: None,
        transform: identity(),
    }
}

pub struct ContainerLayer {
    common: CommonLayer,
    first_child: Option<Layer>,
    last_child: Option<Layer>,
    scissor: Option<Rect<f32>>,
}

pub fn ContainerLayer() -> ContainerLayer {
    ContainerLayer {
        common: CommonLayer(),
        first_child: None,
        last_child: None,
        scissor: None,
    }
}

struct ChildIterator {
    priv current: Option<Layer>,
}

impl Iterator<Layer> for ChildIterator {
    fn next(&mut self) -> Option<Layer> {
        match self.current {
            None => None,
            Some(child) => {
                self.current = child.with_common(|x| x.next_sibling);
                Some(child)
            }
        }
    }
}

impl ContainerLayer {
    pub fn children(&self) -> ChildIterator {
        ChildIterator { current: self.first_child }
    }

    /// Only works when the child is disconnected from the layer tree.
    pub fn add_child(@mut self, new_child: Layer) {
        do new_child.with_common |new_child_common| {
            assert!(new_child_common.parent.is_none());
            assert!(new_child_common.prev_sibling.is_none());
            assert!(new_child_common.next_sibling.is_none());

            new_child_common.parent = Some(ContainerLayerKind(self));

            match self.first_child {
                None => {}
                Some(first_child) => {
                    do first_child.with_common |first_child_common| {
                        assert!(first_child_common.prev_sibling.is_none());
                        first_child_common.prev_sibling = Some(new_child);
                        new_child_common.next_sibling = Some(first_child);
                    }
                }
            }

            self.first_child = Some(new_child);

            match self.last_child {
                None => self.last_child = Some(new_child),
                Some(_) => {}
            }
        }
    }

    pub fn remove_child(@mut self, child: Layer) {
        do child.with_common |child_common| {
            assert!(child_common.parent.is_some());
            match child_common.parent.unwrap() {
                ContainerLayerKind(ref container) => {
                    assert!(mut_ptr_eq(*container, self));
                },
                _ => fail!(~"Invalid parent of child in layer tree"),
            }

            match child_common.next_sibling {
                None => { // this is the last child
                    self.last_child = child_common.prev_sibling;
                },
                Some(ref sibling) => {
                    do sibling.with_common |sibling_common| {
                        sibling_common.prev_sibling = child_common.prev_sibling;
                    }
                }
            }
            match child_common.prev_sibling {
                None => { // this is the first child
                    self.first_child = child_common.next_sibling;
                },
                Some(ref sibling) => {
                    do sibling.with_common |sibling_common| {
                        sibling_common.next_sibling = child_common.next_sibling;
                    }
                }
            }
        }
    }
}

trait TextureManager {
    pub fn get_texture(&self) -> GLuint;
}

pub struct TextureLayer {
    common: CommonLayer,
    manager: @TextureManager,
    size: Size2D<uint>
}

impl TextureLayer {
    pub fn new(manager: @TextureManager, size: Size2D<uint>) -> TextureLayer {
        TextureLayer {
            common: CommonLayer(),
            manager: manager,
            size: size,
        }
    }
}

pub type WithDataFn<'self> = &'self fn(&'self [u8]);

pub trait ImageData {
    fn size(&self) -> Size2D<uint>;

    // NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH.
    fn stride(&self) -> uint;

    fn format(&self) -> Format;
    fn with_data(&self, WithDataFn);
}

pub struct Image {
    data: @ImageData,
    texture: Option<GLuint>,
}

#[unsafe_destructor]
impl Drop for Image {
    fn drop(&self) {
        match self.texture.clone() {
            None => {
                // Nothing to do.
            }
            Some(texture) => {
                delete_textures(&[texture]);
            }
        }
    }
}

impl Image {
    pub fn new(data: @ImageData) -> Image {
        Image { data: data, texture: None }
    }
}

/// Basic image data is a simple image data store that just owns the pixel data in memory.
pub struct BasicImageData {
    size: Size2D<uint>,
    stride: uint,
    format: Format,
    data: ~[u8]
}

impl BasicImageData {
    pub fn new(size: Size2D<uint>, stride: uint, format: Format, data: ~[u8]) ->
            BasicImageData {
        BasicImageData {
            size: size,
            stride: stride,
            format: format,
            data: data
        }
    }
}

impl ImageData for BasicImageData {
    fn size(&self) -> Size2D<uint> { self.size }
    fn stride(&self) -> uint { self.stride }
    fn format(&self) -> Format { self.format }
    fn with_data(&self, f: WithDataFn) { f(self.data) }
}

pub struct ImageLayer {
    common: CommonLayer,
    image: @mut Image,
}

impl ImageLayer {
    // FIXME: Workaround for cross-crate bug
    pub fn set_image(&mut self, new_image: @mut Image) {
        self.image = new_image;
    }
}

pub fn ImageLayer(image: @mut Image) -> ImageLayer {
    ImageLayer {
        common : CommonLayer(),
        image : image,
    }
}

pub struct TiledImageLayer {
    common: CommonLayer,
    tiles: @mut ~[@mut Image],
    tiles_across: uint,
}

pub fn TiledImageLayer(in_tiles: &[@mut Image], tiles_across: uint) -> TiledImageLayer {
    let tiles = @mut ~[];
    for tile in in_tiles.iter() {
        tiles.push(*tile);
    }

    TiledImageLayer {
        common: CommonLayer(),
        tiles: tiles,
        tiles_across: tiles_across
    }
}

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

use geom::matrix::{Matrix4, identity};
use geom::size::Size2D;
use geom::rect::Rect;
use opengles::gl2::{GLuint, delete_textures};
use std::managed::mut_ptr_eq;

pub enum Format {
    ARGB32Format,
    RGB24Format
}

pub enum Layer {
    ContainerLayerKind(@mut ContainerLayer),
    TextureLayerKind(@mut TextureLayer),
    ImageLayerKind(@mut ImageLayer),
    TiledImageLayerKind(@mut TiledImageLayer)
}

impl Layer {
    pub fn with_common<T>(&self, f: &fn(&mut CommonLayer) -> T) -> T {
        match *self {
            ContainerLayerKind(container_layer) => f(&mut container_layer.common),
            TextureLayerKind(texture_layer) => f(&mut texture_layer.common),
            ImageLayerKind(image_layer) => f(&mut image_layer.common),
            TiledImageLayerKind(tiled_image_layer) => f(&mut tiled_image_layer.common)
        }
    }
}

pub struct CommonLayer {
    parent: Option<Layer>,
    prev_sibling: Option<Layer>,
    next_sibling: Option<Layer>,

    transform: Matrix4<f32>,
}

impl CommonLayer {
    // FIXME: Workaround for cross-crate bug regarding mutability of class fields
    pub fn set_transform(&mut self, new_transform: Matrix4<f32>) {
        self.transform = new_transform;
    }
}

pub fn CommonLayer() -> CommonLayer {
    CommonLayer {
        parent: None,
        prev_sibling: None,
        next_sibling: None,
        transform: identity(),
    }
}

pub struct ContainerLayer {
    common: CommonLayer,
    first_child: Option<Layer>,
    last_child: Option<Layer>,
    scissor: Option<Rect<f32>>,
}

pub fn ContainerLayer() -> ContainerLayer {
    ContainerLayer {
        common: CommonLayer(),
        first_child: None,
        last_child: None,
        scissor: None,
    }
}

struct ChildIterator {
    priv current: Option<Layer>,
}

impl Iterator<Layer> for ChildIterator {
    fn next(&mut self) -> Option<Layer> {
        match self.current {
            None => None,
            Some(child) => {
                self.current = child.with_common(|x| x.next_sibling);
                Some(child)
            }
        }
    }
}

impl ContainerLayer {
    pub fn children(&self) -> ChildIterator {
        ChildIterator { current: self.first_child }
    }

    /// Only works when the child is disconnected from the layer tree.
    pub fn add_child(@mut self, new_child: Layer) {
        do new_child.with_common |new_child_common| {
            assert!(new_child_common.parent.is_none());
            assert!(new_child_common.prev_sibling.is_none());
            assert!(new_child_common.next_sibling.is_none());

            new_child_common.parent = Some(ContainerLayerKind(self));

            match self.first_child {
                None => {}
                Some(first_child) => {
                    do first_child.with_common |first_child_common| {
                        assert!(first_child_common.prev_sibling.is_none());
                        first_child_common.prev_sibling = Some(new_child);
                        new_child_common.next_sibling = Some(first_child);
                    }
                }
            }

            self.first_child = Some(new_child);

            match self.last_child {
                None => self.last_child = Some(new_child),
                Some(_) => {}
            }
        }
    }

    pub fn remove_child(@mut self, child: Layer) {
        do child.with_common |child_common| {
            assert!(child_common.parent.is_some());
            match child_common.parent.unwrap() {
                ContainerLayerKind(ref container) => {
                    assert!(mut_ptr_eq(*container, self));
                },
                _ => fail!(~"Invalid parent of child in layer tree"),
            }

            match child_common.next_sibling {
                None => { // this is the last child
                    self.last_child = child_common.prev_sibling;
                },
                Some(ref sibling) => {
                    do sibling.with_common |sibling_common| {
                        sibling_common.prev_sibling = child_common.prev_sibling;
                    }
                }
            }
            match child_common.prev_sibling {
                None => { // this is the first child
                    self.first_child = child_common.next_sibling;
                },
                Some(ref sibling) => {
                    do sibling.with_common |sibling_common| {
                        sibling_common.next_sibling = child_common.next_sibling;
                    }
                }
            }
        }
    }
}

pub trait TextureManager {
    fn get_texture(&self) -> GLuint;
}

pub struct TextureLayer {
    common: CommonLayer,
    manager: @TextureManager,
    size: Size2D<uint>
}

impl TextureLayer {
    pub fn new(manager: @TextureManager, size: Size2D<uint>) -> TextureLayer {
        TextureLayer {
            common: CommonLayer(),
            manager: manager,
            size: size,
        }
    }
}

pub type WithDataFn<'self> = &'self fn(&'self [u8]);

pub trait ImageData {
    fn size(&self) -> Size2D<uint>;

    // NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH.
    fn stride(&self) -> uint;

    fn format(&self) -> Format;
    fn with_data(&self, WithDataFn);
}

pub struct Image {
    data: @ImageData,
    texture: Option<GLuint>,
}

#[unsafe_destructor]
impl Drop for Image {
    fn drop(&self) {
        match self.texture.clone() {
            None => {
                // Nothing to do.
            }
            Some(texture) => {
                delete_textures(&[texture]);
            }
        }
    }
}

impl Image {
    pub fn new(data: @ImageData) -> Image {
        Image { data: data, texture: None }
    }
}

/// Basic image data is a simple image data store that just owns the pixel data in memory.
pub struct BasicImageData {
    size: Size2D<uint>,
    stride: uint,
    format: Format,
    data: ~[u8]
}

impl BasicImageData {
    pub fn new(size: Size2D<uint>, stride: uint, format: Format, data: ~[u8]) ->
            BasicImageData {
        BasicImageData {
            size: size,
            stride: stride,
            format: format,
            data: data
        }
    }
}

impl ImageData for BasicImageData {
    fn size(&self) -> Size2D<uint> { self.size }
    fn stride(&self) -> uint { self.stride }
    fn format(&self) -> Format { self.format }
    fn with_data(&self, f: WithDataFn) { f(self.data) }
}

pub struct ImageLayer {
    common: CommonLayer,
    image: @mut Image,
}

impl ImageLayer {
    // FIXME: Workaround for cross-crate bug
    pub fn set_image(&mut self, new_image: @mut Image) {
        self.image = new_image;
    }
}

pub fn ImageLayer(image: @mut Image) -> ImageLayer {
    ImageLayer {
        common : CommonLayer(),
        image : image,
    }
}

pub struct TiledImageLayer {
    common: CommonLayer,
    tiles: @mut ~[@mut Image],
    tiles_across: uint,
}

pub fn TiledImageLayer(in_tiles: &[@mut Image], tiles_across: uint) -> TiledImageLayer {
    let tiles = @mut ~[];
    for tile in in_tiles.iter() {
        tiles.push(*tile);
    }

    TiledImageLayer {
        common: CommonLayer(),
        tiles: tiles,
        tiles_across: tiles_across
    }
}

<|endoftext|>


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

use analysis::rust_type::bounds_rust_type;
use case::CaseExt;
use analysis;
use library;
use env::Env;
use nameutil;
use super::child_properties;
use super::function;
use super::general;
use super::properties;
use super::signal;
use super::trait_impls;
use super::trampoline;

pub fn generate(
    w: &mut Write,
    env: &Env,
    analysis: &analysis::object::Info,
    generate_display_trait: bool,
) -> Result<()> {
    try!(general::start_comments(w, &env.config));
    try!(general::uses(w, env, &analysis.imports));

    try!(general::define_object_type(
        w,
        env,
        &analysis.name,
        &analysis.c_type,
        &analysis.c_class_type.as_ref().map(|s| &s[..]),
        &analysis.rust_class_type.as_ref().map(|s| &s[..]),
        &analysis.get_type,
        analysis.is_interface,
        &analysis.supertypes,
    ));

    if need_generate_inherent(analysis) {
        try!(writeln!(w));
        try!(write!(w, "impl {} {{", analysis.name));
        for func_analysis in &analysis.constructors() {
            try!(function::generate(w, env, func_analysis, false, false, 1));
        }

        if !need_generate_trait(analysis) {
            for func_analysis in &analysis.methods() {
                try!(function::generate(w, env, func_analysis, false, false, 1));
            }

            for property in &analysis.properties {
                try!(properties::generate(w, env, property, false, false, 1));
            }

            for child_property in &analysis.child_properties {
                try!(child_properties::generate(
                    w,
                    env,
                    child_property,
                    false,
                    false,
                    1,
                ));
            }
        }

        for func_analysis in &analysis.functions() {
            try!(function::generate(w, env, func_analysis, false, false, 1));
        }

        if !need_generate_trait(analysis) {
            for signal_analysis in analysis
                .signals
                .iter()
                .chain(analysis.notify_signals.iter())
            {
                try!(signal::generate(
                    w,
                    env,
                    signal_analysis,
                    &analysis.trampolines,
                    false,
                    false,
                    1,
                ));
            }
        }

        try!(writeln!(w, "}}"));

        try!(general::declare_default_from_new(
            w,
            env,
            &analysis.name,
            &analysis.functions
        ));
    }

    try!(trait_impls::generate(
        w,
        &analysis.name,
        &analysis.functions,
        &analysis.specials,
        if need_generate_trait(analysis) {
            Some(&analysis.trait_name)
        } else {
            None
        },
    ));

    if analysis.concurrency != library::Concurrency::None {
        try!(writeln!(w));
    }

    // TODO: include parent and writable properties.
    if !analysis.builder_properties.is_empty() {
        let mut methods = vec![];
        let mut properties = vec![];
        writeln!(w, "#[cfg(any(feature = \"builders\", feature = \"dox\"))]
pub struct {}Builder {{", analysis.name)?;
        for property in &analysis.builder_properties {
            match bounds_rust_type(env, property.typ) {
                Ok(type_string) => {
                    let attribute_type =
                        match type_string.as_str() {
                            "str" => "String",
                            _ => &type_string,
                        };
                    let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
                    if let Some(version) = property.version {
                        writeln!(w, "    #[cfg(any(feature = \"{}\", feature = \"dox\"))]", version.to_feature())?;
                    }
                    writeln!(w, "    {}: Option<{}>,", name, attribute_type)?;
                    let prefix =
                        if let Some(version) = property.version {
                            format!("    #[cfg(any(feature = \"{}\", feature = \"dox\"))]\n", version.to_feature())
                        }
                        else {
                            String::new()
                        };
                    let (type_string, conversion) =
                        match type_string.as_str() {
                            "str" => ("&str", ".to_string()"),
                            _ => (&*type_string, ""),
                        };
                    methods.push(format!("\n{}    pub fn {name}(mut self, {name}: {}) -> Self {{
    self.{name} = Some({name}{});
    self
}}", prefix, type_string, conversion, name=name));
                    properties.push(property);
                },
                Err(_) => writeln!(w, "    //{}: /*Unknown type*/,", property.name)?,
            }
        }
        writeln!(w, "}}\n

#[cfg(any(feature = \"builders\", feature = \"dox\"))]
impl {}Builder {{
    pub fn new() -> Self {{
        Self {{", analysis.name)?;
        for property in &properties {
            if let Some(version) = property.version {
                writeln!(w, "            #[cfg(any(feature = \"{}\", feature = \"dox\"))]", version.to_feature())?;
            }
            let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
            writeln!(w, "            {}: None,", name)?;
        }
        writeln!(w, "        }}
    }}

    pub fn build(self) -> {} {{
        let mut properties: Vec<(&str, &dyn ToValue)> = vec![];", analysis.name)?;
        for property in &properties {
            let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
            if let Some(version) = property.version {
                writeln!(w,
"        #[cfg(any(feature = \"{}\", feature = \"dox\"))]
        {{", version.to_feature())?;
            }
            writeln!(w,
"        if let Some(ref {property}) = self.{property} {{
            properties.push((\"{}\", {property}));
        }}", property = name)?;
            if property.version.is_some() {
                writeln!(w, "        }}")?;
            }
        }
        writeln!(w,
"        crate::Object::new({}::static_type(), &properties).expect(\"object new\").downcast().expect(\"downcast\")
    }}", analysis.name)?;
        for method in methods {
            writeln!(w, "{}", method)?;
        }
        writeln!(w, "}}")?;
    }

    match analysis.concurrency {
        library::Concurrency::Send | library::Concurrency::SendSync => {
            try!(writeln!(w, "unsafe impl Send for {} {{}}", analysis.name));
        }
        library::Concurrency::SendUnique => {
            if env.namespaces.is_glib_crate {
                try!(writeln!(w, "unsafe impl ::SendUnique for {} {{", analysis.name));
            } else {
                try!(writeln!(w, "unsafe impl glib::SendUnique for {} {{", analysis.name));
            }

            try!(writeln!(w, "    fn is_unique(&self) -> bool {{"));
            try!(writeln!(w, "        self.ref_count() == 1"));
            try!(writeln!(w, "    }}"));

            try!(writeln!(w, "}}"));
        },
        _ => (),
    }

    if let library::Concurrency::SendSync = analysis.concurrency {
        try!(writeln!(w, "unsafe impl Sync for {} {{}}", analysis.name));
    }

    if !analysis.final_type {
        try!(writeln!(w));
        try!(writeln!(w, "pub const NONE_{}: Option<&{}> = None;", analysis.name.to_snake().to_uppercase(), analysis.name));
    }

    if need_generate_trait(analysis) {
        try!(writeln!(w));
        try!(generate_trait(w, env, analysis));
    }

    if !analysis.trampolines.is_empty() {
        for trampoline in &analysis.trampolines {
            try!(trampoline::generate(
                w,
                env,
                trampoline,
                need_generate_trait(analysis),
                &analysis.name,
            ));
        }
    }

    if generate_display_trait {
        try!(writeln!(
            w,
            "\nimpl fmt::Display for {} {{",
            analysis.name,
        ));
        // Generate Display trait implementation.
        try!(writeln!(w, "\tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{\n\
                            \t\twrite!(f, \"{}\")\n\
                          \t}}\n\
                        }}", analysis.name));
    }

    Ok(())
}

fn generate_trait(
    w: &mut Write,
    env: &Env,
    analysis: &analysis::object::Info,
) -> Result<()> {
    try!(write!(w, "pub trait {}: 'static {{", analysis.trait_name));

    for func_analysis in &analysis.methods() {
        try!(function::generate(w, env, func_analysis, true, true, 1));
    }
    for property in &analysis.properties {
        try!(properties::generate(w, env, property, true, true, 1));
    }
    for child_property in &analysis.child_properties {
        try!(child_properties::generate(
            w,
            env,
            child_property,
            true,
            true,
            1,
        ));
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        try!(signal::generate(
            w,
            env,
            signal_analysis,
            &analysis.trampolines,
            true,
            true,
            1,
        ));
    }
    try!(writeln!(w, "}}"));

    try!(writeln!(w));
    try!(write!(
        w,
        "impl<O: IsA<{}>> {} for O {{",
        analysis.name,
        analysis.trait_name,
    ));

    for func_analysis in &analysis.methods() {
        try!(function::generate(w, env, func_analysis, true, false, 1));
    }
    for property in &analysis.properties {
        try!(properties::generate(w, env, property, true, false, 1));
    }
    for child_property in &analysis.child_properties {
        try!(child_properties::generate(
            w,
            env,
            child_property,
            true,
            false,
            1,
        ));
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        try!(signal::generate(
            w,
            env,
            signal_analysis,
            &analysis.trampolines,
            true,
            false,
            1,
        ));
    }
    try!(writeln!(w, "}}"));

    Ok(())
}

fn need_generate_inherent(analysis: &analysis::object::Info) -> bool {
    analysis.has_constructors || analysis.has_functions || !need_generate_trait(analysis)
}

fn need_generate_trait(analysis: &analysis::object::Info) -> bool {
    analysis.generate_trait
}

pub fn generate_reexports(
    env: &Env,
    analysis: &analysis::object::Info,
    module_name: &str,
    contents: &mut Vec<String>,
    traits: &mut Vec<String>,
) {
    let mut cfgs: Vec<String> = Vec::new();
    if let Some(cfg) = general::cfg_condition_string(&analysis.cfg_condition, false, 0) {
        cfgs.push(cfg);
    }
    if let Some(cfg) = general::version_condition_string(env, analysis.version, false, 0) {
        cfgs.push(cfg);
    }
    contents.push("".to_owned());
    contents.extend_from_slice(&cfgs);
    contents.push(format!("mod {};", module_name));
    contents.extend_from_slice(&cfgs);

    let none_type = if !analysis.final_type {
        format!(", NONE_{}", analysis.name.to_snake().to_uppercase())
    } else {
        String::new()
    };

    if let Some(ref class_name) = analysis.rust_class_type {
        contents.push(format!("pub use self::{}::{{{}, {}{}}};", module_name, analysis.name, class_name, none_type));
    } else {
        contents.push(format!("pub use self::{}::{{{}{}}};", module_name, analysis.name, none_type));
    }
    if need_generate_trait(analysis) {
        contents.extend_from_slice(&cfgs);
        contents.push(format!(
            "pub use self::{}::{};",
            module_name,
            analysis.trait_name
        ));
        for cfg in &cfgs {
            traits.push(format!("\t{}", cfg));
        }
        traits.push(format!("\tpub use super::{};", analysis.trait_name));
    }

    if !analysis.builder_properties.is_empty() {
        contents.extend_from_slice(&cfgs);
        contents.push(format!("#[cfg(any(feature = \"builders\", feature = \"dox\"))]
pub use self::{}::{}Builder;", module_name, analysis.name));
    }
}
<commit_msg>Use version_condition<commit_after>use std::io::{Result, Write};

use analysis::rust_type::rust_type;
use codegen::general::{version_condition, version_condition_string};
use case::CaseExt;
use analysis;
use library;
use env::Env;
use nameutil;
use super::child_properties;
use super::function;
use super::general;
use super::properties;
use super::signal;
use super::trait_impls;
use super::trampoline;

pub fn generate(
    w: &mut Write,
    env: &Env,
    analysis: &analysis::object::Info,
    generate_display_trait: bool,
) -> Result<()> {
    try!(general::start_comments(w, &env.config));
    try!(general::uses(w, env, &analysis.imports));

    try!(general::define_object_type(
        w,
        env,
        &analysis.name,
        &analysis.c_type,
        &analysis.c_class_type.as_ref().map(|s| &s[..]),
        &analysis.rust_class_type.as_ref().map(|s| &s[..]),
        &analysis.get_type,
        analysis.is_interface,
        &analysis.supertypes,
    ));

    if need_generate_inherent(analysis) {
        try!(writeln!(w));
        try!(write!(w, "impl {} {{", analysis.name));
        for func_analysis in &analysis.constructors() {
            try!(function::generate(w, env, func_analysis, false, false, 1));
        }

        if !need_generate_trait(analysis) {
            for func_analysis in &analysis.methods() {
                try!(function::generate(w, env, func_analysis, false, false, 1));
            }

            for property in &analysis.properties {
                try!(properties::generate(w, env, property, false, false, 1));
            }

            for child_property in &analysis.child_properties {
                try!(child_properties::generate(
                    w,
                    env,
                    child_property,
                    false,
                    false,
                    1,
                ));
            }
        }

        for func_analysis in &analysis.functions() {
            try!(function::generate(w, env, func_analysis, false, false, 1));
        }

        if !need_generate_trait(analysis) {
            for signal_analysis in analysis
                .signals
                .iter()
                .chain(analysis.notify_signals.iter())
            {
                try!(signal::generate(
                    w,
                    env,
                    signal_analysis,
                    &analysis.trampolines,
                    false,
                    false,
                    1,
                ));
            }
        }

        try!(writeln!(w, "}}"));

        try!(general::declare_default_from_new(
            w,
            env,
            &analysis.name,
            &analysis.functions
        ));
    }

    try!(trait_impls::generate(
        w,
        &analysis.name,
        &analysis.functions,
        &analysis.specials,
        if need_generate_trait(analysis) {
            Some(&analysis.trait_name)
        } else {
            None
        },
    ));

    if analysis.concurrency != library::Concurrency::None {
        try!(writeln!(w));
    }

    // TODO: include parent and writable properties.
    if !analysis.builder_properties.is_empty() {
        let mut methods = vec![];
        let mut properties = vec![];
        writeln!(w, "#[cfg(any(feature = \"builders\", feature = \"dox\"))]
pub struct {}Builder {{", analysis.name)?;
        for property in &analysis.builder_properties {
            match rust_type(env, property.typ) {
                Ok(type_string) => {
                    let type_string =
                        match type_string.as_str() {
                            "GString" => "String",
                            "Vec<GString>" => "Vec<String>",
                            typ => typ,
                        };
                    let (param_type, conversion) =
                        match type_string {
                            "String" => ("&str", ".to_string()"),
                            typ => (typ, ""),
                        };
                    let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
                    version_condition(w, env, property.version, false, 1)?;
                    writeln!(w, "    {}: Option<{}>,", name, type_string)?;
                    let prefix = version_condition_string(env, property.version, false, 1).unwrap_or_default();
                    methods.push(format!("\n{prefix}    pub fn {name}(mut self, {name}: {param_type}) -> Self {{
        self.{name} = Some({name}{conversion});
        self
    }}", prefix=prefix, param_type=param_type, name=name, conversion=conversion));
                    properties.push(property);
                },
                Err(_) => writeln!(w, "    //{}: /*Unknown type*/,", property.name)?,
            }
        }
        writeln!(w, "}}\n

#[cfg(any(feature = \"builders\", feature = \"dox\"))]
impl {}Builder {{
    pub fn new() -> Self {{
        Self {{", analysis.name)?;
        for property in &properties {
            version_condition(w, env, property.version, false, 3)?;
            let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
            writeln!(w, "            {}: None,", name)?;
        }
        writeln!(w, "        }}
    }}

    pub fn build(self) -> {} {{
        let mut properties: Vec<(&str, &dyn ToValue)> = vec![];", analysis.name)?;
        for property in &properties {
            let name = nameutil::mangle_keywords(nameutil::signal_to_snake(&property.name));
            version_condition(w, env, property.version, false, 2)?;
            if property.version.is_some() {
                writeln!(w, "        {{")?;
            }
            writeln!(w,
"        if let Some(ref {property}) = self.{property} {{
            properties.push((\"{}\", {property}));
        }}", property = name)?;
            if property.version.is_some() {
                writeln!(w, "        }}")?;
            }
        }
        writeln!(w,
"        crate::Object::new({}::static_type(), &properties).expect(\"object new\").downcast().expect(\"downcast\")
    }}", analysis.name)?;
        for method in methods {
            writeln!(w, "{}", method)?;
        }
        writeln!(w, "}}")?;
    }

    match analysis.concurrency {
        library::Concurrency::Send | library::Concurrency::SendSync => {
            try!(writeln!(w, "unsafe impl Send for {} {{}}", analysis.name));
        }
        library::Concurrency::SendUnique => {
            if env.namespaces.is_glib_crate {
                try!(writeln!(w, "unsafe impl ::SendUnique for {} {{", analysis.name));
            } else {
                try!(writeln!(w, "unsafe impl glib::SendUnique for {} {{", analysis.name));
            }

            try!(writeln!(w, "    fn is_unique(&self) -> bool {{"));
            try!(writeln!(w, "        self.ref_count() == 1"));
            try!(writeln!(w, "    }}"));

            try!(writeln!(w, "}}"));
        },
        _ => (),
    }

    if let library::Concurrency::SendSync = analysis.concurrency {
        try!(writeln!(w, "unsafe impl Sync for {} {{}}", analysis.name));
    }

    if !analysis.final_type {
        try!(writeln!(w));
        try!(writeln!(w, "pub const NONE_{}: Option<&{}> = None;", analysis.name.to_snake().to_uppercase(), analysis.name));
    }

    if need_generate_trait(analysis) {
        try!(writeln!(w));
        try!(generate_trait(w, env, analysis));
    }

    if !analysis.trampolines.is_empty() {
        for trampoline in &analysis.trampolines {
            try!(trampoline::generate(
                w,
                env,
                trampoline,
                need_generate_trait(analysis),
                &analysis.name,
            ));
        }
    }

    if generate_display_trait {
        try!(writeln!(
            w,
            "\nimpl fmt::Display for {} {{",
            analysis.name,
        ));
        // Generate Display trait implementation.
        try!(writeln!(w, "\tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{\n\
                            \t\twrite!(f, \"{}\")\n\
                          \t}}\n\
                        }}", analysis.name));
    }

    Ok(())
}

fn generate_trait(
    w: &mut Write,
    env: &Env,
    analysis: &analysis::object::Info,
) -> Result<()> {
    try!(write!(w, "pub trait {}: 'static {{", analysis.trait_name));

    for func_analysis in &analysis.methods() {
        try!(function::generate(w, env, func_analysis, true, true, 1));
    }
    for property in &analysis.properties {
        try!(properties::generate(w, env, property, true, true, 1));
    }
    for child_property in &analysis.child_properties {
        try!(child_properties::generate(
            w,
            env,
            child_property,
            true,
            true,
            1,
        ));
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        try!(signal::generate(
            w,
            env,
            signal_analysis,
            &analysis.trampolines,
            true,
            true,
            1,
        ));
    }
    try!(writeln!(w, "}}"));

    try!(writeln!(w));
    try!(write!(
        w,
        "impl<O: IsA<{}>> {} for O {{",
        analysis.name,
        analysis.trait_name,
    ));

    for func_analysis in &analysis.methods() {
        try!(function::generate(w, env, func_analysis, true, false, 1));
    }
    for property in &analysis.properties {
        try!(properties::generate(w, env, property, true, false, 1));
    }
    for child_property in &analysis.child_properties {
        try!(child_properties::generate(
            w,
            env,
            child_property,
            true,
            false,
            1,
        ));
    }
    for signal_analysis in analysis
        .signals
        .iter()
        .chain(analysis.notify_signals.iter())
    {
        try!(signal::generate(
            w,
            env,
            signal_analysis,
            &analysis.trampolines,
            true,
            false,
            1,
        ));
    }
    try!(writeln!(w, "}}"));

    Ok(())
}

fn need_generate_inherent(analysis: &analysis::object::Info) -> bool {
    analysis.has_constructors || analysis.has_functions || !need_generate_trait(analysis)
}

fn need_generate_trait(analysis: &analysis::object::Info) -> bool {
    analysis.generate_trait
}

pub fn generate_reexports(
    env: &Env,
    analysis: &analysis::object::Info,
    module_name: &str,
    contents: &mut Vec<String>,
    traits: &mut Vec<String>,
) {
    let mut cfgs: Vec<String> = Vec::new();
    if let Some(cfg) = general::cfg_condition_string(&analysis.cfg_condition, false, 0) {
        cfgs.push(cfg);
    }
    if let Some(cfg) = general::version_condition_string(env, analysis.version, false, 0) {
        cfgs.push(cfg);
    }
    contents.push("".to_owned());
    contents.extend_from_slice(&cfgs);
    contents.push(format!("mod {};", module_name));
    contents.extend_from_slice(&cfgs);

    let none_type = if !analysis.final_type {
        format!(", NONE_{}", analysis.name.to_snake().to_uppercase())
    } else {
        String::new()
    };

    if let Some(ref class_name) = analysis.rust_class_type {
        contents.push(format!("pub use self::{}::{{{}, {}{}}};", module_name, analysis.name, class_name, none_type));
    } else {
        contents.push(format!("pub use self::{}::{{{}{}}};", module_name, analysis.name, none_type));
    }
    if need_generate_trait(analysis) {
        contents.extend_from_slice(&cfgs);
        contents.push(format!(
            "pub use self::{}::{};",
            module_name,
            analysis.trait_name
        ));
        for cfg in &cfgs {
            traits.push(format!("\t{}", cfg));
        }
        traits.push(format!("\tpub use super::{};", analysis.trait_name));
    }

    if !analysis.builder_properties.is_empty() {
        contents.extend_from_slice(&cfgs);
        contents.push(format!("#[cfg(any(feature = \"builders\", feature = \"dox\"))]
pub use self::{}::{}Builder;", module_name, analysis.name));
    }
}
<|endoftext|>


<commit_before>use bosun::{Metadata, Rate, Sample, Tags};
use collectors::*;
use config::Config;

use regex::Regex;
use std::collections::HashMap;
use std::process::{Command, Output};
use std::io::Result as IoResult;

static METRIC_NAME_GC: &'static str = "jvm.gc.stats";

#[derive(Debug)]
#[derive(Clone)]
#[derive(RustcDecodable)]
#[allow(non_snake_case)]
pub struct JvmConfig {
    Command: String,
    Name: String,
}

pub struct Jvm {
    id: Id,
    jvms: Vec<JvmConfig>,
    metadata: HashMap<String, Metadata>,
}

pub fn create_instances(config: &Config) -> Vec<Box<Collector + Send>> {
    if !config.Jvm.is_empty() {
        let id = "jvm".to_string();
        info!("Created instance of JVM collector: {}", id);

        let metadata = metadata();
        let collector = Jvm { id: id, jvms: config.Jvm.clone(), metadata: metadata };
        vec![Box::new(collector)]
    } else {
        Vec::new()
    }
}

impl Collector for Jvm {
    fn init(&mut self) -> Result<(), Box<Error>> {
        let result = Command::new("/usr/bin/jps").arg("-help").output();
        if let Err(err) = handle_command_output("jps", result) {
            return Err(Box::new(err))
        };
        let result = Command::new("/usr/bin/jstat").arg("-help").output();
        if let Err(err) = handle_command_output("jps", result) {
            return Err(Box::new(err))
        };

        Ok(())
    }

    fn id(&self) -> &Id {
        &self.id
    }

    fn collect(&self) -> Result<Vec<Sample>, Error> {
        let jvm_processes = try!(get_jps());
        let results: Vec<Result<Vec<GcStat>, Error>> = jvm_processes.iter()
            .map(|jp| identify_jvms(&self.jvms, jp))
            .filter(|jvm| jvm.name.is_some())
            .map(|jvm| sample_gc_stats(&jvm))
            .collect();

        let (oks, fails): (Vec<_>, Vec<_>) = results.into_iter().partition(Result::is_ok);
        if !fails.is_empty() {
            for f in fails {
                if let Err(err) = f {
                    warn!("Failed to sample gc stats: {}", err);
                }
            }
        }

        let result = oks.into_iter()
            .flat_map(|ok| ok) // Res -> Vec
            .flat_map(|gcs| gcs.into_iter()) // Vec<Vec> -> Vec
            .filter_map(|gc| gcstat_to_sample(&self.metadata, gc)) // None, Some(GC), None -> Some(Sample)
            .collect();
        trace!("Collected these GC samples: '{:#?}'", result);

        Ok(result)
    }

    fn shutdown(&mut self) {}

    fn metadata(&self) -> Vec<Metadata> {
        let mut metadata = metadata();
        let result = metadata.drain().map(|(_, v)| v).collect();
        result
    }
}

fn metadata() -> HashMap<String, Metadata> {
    let mut metadata: HashMap<String, Metadata> = HashMap::new();
    metadata.insert("S0C".to_string(),
        Metadata::new(format!("{}.survivor_space_0_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "S0C: Current survivor space 1 capacity"));
    metadata.insert("S1C".to_string(),
        Metadata::new(format!("{}.survivor_space_1_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "S1C: Current survivor space 1 capacity"));
    metadata.insert("S0U".to_string(),
        Metadata::new(format!("{}.survivor_space_0_utilization", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "S0U: Survivor space 1 utilization"));
    metadata.insert("S1U".to_string(),
        Metadata::new(format!("{}.survivor_space_1_utilization", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "S1U: Survivor space 1 utilization"));
    metadata.insert("EC".to_string(),
        Metadata::new(format!("{}.current_eden_space_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "EC: Current eden space capacity"));
    metadata.insert("EU".to_string(),
        Metadata::new(format!("{}.eden_space_utilization", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "EU: Eden space utilization"));
    metadata.insert("OC".to_string(),
        Metadata::new(format!("{}.current_old_space_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "OC: Current old capacity"));
    metadata.insert("OU".to_string(),
        Metadata::new(format!("{}.old_space_utilization", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "OU: Old space utilization"));
    metadata.insert("PC".to_string(),
        Metadata::new(format!("{}.current_permanent_space_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "PC: Current permanent space capacity"));
    metadata.insert("PU".to_string(),
        Metadata::new(format!("{}.permanent_space_utilization", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "PU: permanent space utilization"));
    metadata.insert("MC".to_string(),
        Metadata::new(format!("{}.metaspace_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "MC: metaspace capacity"));
    metadata.insert("MU".to_string(),
        Metadata::new(format!("{}.metaspace_utilization", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "MU: metaspace utilization"));
    metadata.insert("CCSC".to_string(),
        Metadata::new(format!("{}.compressed_class_space_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "CCSC: Compressed class space capacity"));
    metadata.insert("CCSU".to_string(),
        Metadata::new(format!("{}.compressed_class_space_used", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "CCSU: Compressed class space used"));
    metadata.insert("YGC".to_string(),
        Metadata::new(format!("{}.young_generation_gc_events", METRIC_NAME_GC),
                      Rate::Counter,
                      "Event",
                      "YGC: Number of young generation garbage collection events"));
    metadata.insert("YGCT".to_string(),
        Metadata::new(format!("{}.young_generation_gc_time", METRIC_NAME_GC),
                      Rate::Counter,
                      "s",
                      "YGCT: Young generation garbage collection time"));
    metadata.insert("FGC".to_string(),
        Metadata::new(format!("{}.full_gc_events", METRIC_NAME_GC),
                      Rate::Counter,
                      "Event",
                      "FGC: Number of full GC events."));
    metadata.insert("FGCT".to_string(),
        Metadata::new(format!("{}.full_gc_time", METRIC_NAME_GC),
                      Rate::Counter,
                      "s",
                      "FGCT: Full garbage collection time"));
    metadata.insert("GCT".to_string(),
        Metadata::new(format!("{}.total_gc_time", METRIC_NAME_GC),
                      Rate::Counter,
                      "s",
                      "GCT: Total garbage collection time"));

    metadata
}

fn handle_command_output(command: &str, result: IoResult<Output>) -> Result<Output, Error> {
    match result {
        Ok(output) => {
            if output.status.success() {
                debug!("Successfully found and run {}.", command);
                Ok(output)
            } else {
                let exit_code = output.status.code().map_or("<received signal>".to_string(), |i| format!("{}", i));
                let stdout = String::from_utf8_lossy(&output.stdout);
                let stderr = String::from_utf8_lossy(&output.stderr);
                let msg = format!("Running {} returned exit code {}: out '{}', err '{}'.", command, exit_code, stdout, stderr);
                debug!("{}", msg);
                Err(Error::InitError(msg))
            }
        },
        Err(err) => {
            let msg = format!("Failed to run {}, because '{}'.", command, err.description());
            debug!("{}", msg);
            Err(Error::InitError(msg))
        },
    }
}

#[derive(Debug)]
struct JvmProcess {
    pid: u16,
    class: String,
    cmdline: String,
}

fn get_jps() -> Result<Vec<JvmProcess>, Error>{
    let result = execute_jps();
    let output = try!(handle_command_output("jps", result));
    let stdout = String::from_utf8_lossy(&output.stdout);
    let lines: Vec<&str> = stdout.lines().collect();
    if lines.is_empty() {
        let msg = format!("Failed to parse jps output");
        trace!("Failed to parse jps output for lines: '{}'", stdout);
        return Err(Error::CollectionError(msg));
    }

    let mut jps = Vec::new();
    for line in lines {
        let cols: Vec<&str> = line.split_whitespace().collect();
        if cols.len() < 2 {
            let msg = format!("Failed to parse jps output; expected 'PID CLASS CMDLINE'");
            trace!("Failed to parse jps output for lines: '{}'", stdout);
            return Err(Error::CollectionError(msg));
        }
        let pid: u16 = try!(cols[0].parse::<u16>());
        let jp = JvmProcess { pid: pid, class: cols[1].to_string(), cmdline: cols[2..].join(" ").to_string() };
        trace!("Found JVM Process '{:?}'", jp);
        jps.push(jp)
    }
    Ok(jps)
}

fn execute_jps() -> IoResult<Output> {
    // TODO: use timeout for execution
    Command::new("/usr/bin/jps").arg("-vl").output()
}

#[derive(Debug)]
struct IdentifiedJvm {
    pid: u16,
    name: Option<String>,
}

fn identify_jvms(jvm_configs: &Vec<JvmConfig>, jp: &JvmProcess) -> IdentifiedJvm {
    // TODO: Use regex set for a single scan
    // TODO: Use func combinators
    let mut name = None;
    for jvm_config in jvm_configs {
        // TODO: Make this safe
        let re = Regex::new(&jvm_config.Command).unwrap();
        if re.is_match(&jp.class) || re.is_match(&jp.cmdline) {
            name = Some(jvm_config.Name.clone());
            break;
        }
    }
    IdentifiedJvm {pid: jp.pid, name: name }
}

#[derive(Debug)]
struct GcStat {
    jvm_name: String,
    name: String,
    value: f64,
}

fn sample_gc_stats(jvm: &IdentifiedJvm) -> Result<Vec<GcStat>, Error> {
    let result = execute_jstat(jvm);
    let output = try!(handle_command_output("jstat", result));
    let stdout = String::from_utf8_lossy(&output.stdout);
    let lines: Vec<&str> = stdout.lines().collect();
    if lines.len() != 2  {
        let msg = format!("Failed to parse jstat output for pid {}", jvm.pid);
        trace!("Failed to parse jstat out for lines: '{}'", stdout);
        return Err(Error::CollectionError(msg));
    }
    let names: Vec<&str> = lines[0].split_whitespace().collect();
    let values: Vec<&str> = lines[1].split_whitespace().collect();

    let mut gcstats = Vec::new();
    for i in 0..values.len() {
        let name = names[i];
        let value = try!(values[i].parse::<f64>());
        // TODO: Unwrap is safe, but only due to the filter in the main algorithm
        let gcstat = GcStat{ jvm_name: jvm.name.as_ref().unwrap().clone(), name: name.to_string(), value: value };
        trace!("Successfully run gcstat for JVM Process '{:?}': '{:?}'", jvm, gcstat);
        gcstats.push(gcstat);
    }

    Ok(gcstats)
}

fn execute_jstat(jvm: &IdentifiedJvm) -> IoResult<Output> {
    // TODO: use timeout for execution
    let pid = format!("{}", jvm.pid);
    Command::new("/usr/bin/jstat").arg("-gc").arg(pid).output()
}

fn gcstat_to_sample(metadata: &HashMap<String, Metadata>, gcstat: GcStat) -> Option<Sample> {
    let mut tags = Tags::new();
    tags.insert("jvm_name".to_string(), gcstat.jvm_name );
    let metric_name = metadata.get(&gcstat.name).map(|m| m.metric.to_string());
    if let Some(name) = metric_name {
        let sample = Sample::new_with_tags(name, gcstat.value, tags);
        Some(sample)
    } else {
        None
    }
}

<commit_msg>JVM: fixed some todos<commit_after>use bosun::{Metadata, Rate, Sample, Tags};
use collectors::*;
use config::Config;

use regex::Regex;
use std::collections::HashMap;
use std::process::{Command, Output};
use std::io::Result as IoResult;

static METRIC_NAME_GC: &'static str = "jvm.gc.stats";

#[derive(Debug)]
#[derive(Clone)]
#[derive(RustcDecodable)]
#[allow(non_snake_case)]
pub struct JvmConfig {
    Command: String,
    Name: String,
}

pub struct Jvm {
    id: Id,
    jvms: Vec<JvmConfig>,
    metadata: HashMap<String, Metadata>,
}

pub fn create_instances(config: &Config) -> Vec<Box<Collector + Send>> {
    if !config.Jvm.is_empty() {
        let id = "jvm".to_string();
        info!("Created instance of JVM collector: {}", id);

        let metadata = metadata();
        let collector = Jvm { id: id, jvms: config.Jvm.clone(), metadata: metadata };
        vec![Box::new(collector)]
    } else {
        Vec::new()
    }
}

impl Collector for Jvm {
    fn init(&mut self) -> Result<(), Box<Error>> {
        let result = Command::new("/usr/bin/jps").arg("-help").output();
        if let Err(err) = handle_command_output("jps", result) {
            return Err(Box::new(err))
        };
        let result = Command::new("/usr/bin/jstat").arg("-help").output();
        if let Err(err) = handle_command_output("jps", result) {
            return Err(Box::new(err))
        };

        Ok(())
    }

    fn id(&self) -> &Id {
        &self.id
    }

    fn collect(&self) -> Result<Vec<Sample>, Error> {
        let jvm_processes = try!(get_jps());
        let results: Vec<Result<Vec<GcStat>, Error>> = jvm_processes.iter()
            .map(|jp| identify_jvms(&self.jvms, jp))
            .filter(|jvm| jvm.name.is_some())
            .map(|jvm| sample_gc_stats(&jvm))
            .collect();

        let (oks, fails): (Vec<_>, Vec<_>) = results.into_iter().partition(Result::is_ok);
        if !fails.is_empty() {
            for f in fails {
                if let Err(err) = f {
                    warn!("Failed to sample gc stats: {}", err);
                }
            }
        }

        let result = oks.into_iter()
            .flat_map(|ok| ok) // Res -> Vec
            .flat_map(|gcs| gcs.into_iter()) // Vec<Vec> -> Vec
            .filter_map(|gc| gcstat_to_sample(&self.metadata, gc)) // None, Some(GC), None -> Some(Sample)
            .collect();
        trace!("Collected these GC samples: '{:#?}'", result);

        Ok(result)
    }

    fn shutdown(&mut self) {}

    fn metadata(&self) -> Vec<Metadata> {
        let mut metadata = metadata();
        let result = metadata.drain().map(|(_, v)| v).collect();
        result
    }
}

fn metadata() -> HashMap<String, Metadata> {
    let mut metadata: HashMap<String, Metadata> = HashMap::new();
    metadata.insert("S0C".to_string(),
        Metadata::new(format!("{}.survivor_space_0_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "S0C: Current survivor space 1 capacity"));
    metadata.insert("S1C".to_string(),
        Metadata::new(format!("{}.survivor_space_1_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "S1C: Current survivor space 1 capacity"));
    metadata.insert("S0U".to_string(),
        Metadata::new(format!("{}.survivor_space_0_utilization", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "S0U: Survivor space 1 utilization"));
    metadata.insert("S1U".to_string(),
        Metadata::new(format!("{}.survivor_space_1_utilization", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "S1U: Survivor space 1 utilization"));
    metadata.insert("EC".to_string(),
        Metadata::new(format!("{}.current_eden_space_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "EC: Current eden space capacity"));
    metadata.insert("EU".to_string(),
        Metadata::new(format!("{}.eden_space_utilization", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "EU: Eden space utilization"));
    metadata.insert("OC".to_string(),
        Metadata::new(format!("{}.current_old_space_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "OC: Current old capacity"));
    metadata.insert("OU".to_string(),
        Metadata::new(format!("{}.old_space_utilization", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "OU: Old space utilization"));
    metadata.insert("PC".to_string(),
        Metadata::new(format!("{}.current_permanent_space_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "PC: Current permanent space capacity"));
    metadata.insert("PU".to_string(),
        Metadata::new(format!("{}.permanent_space_utilization", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "PU: permanent space utilization"));
    metadata.insert("MC".to_string(),
        Metadata::new(format!("{}.metaspace_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "MC: metaspace capacity"));
    metadata.insert("MU".to_string(),
        Metadata::new(format!("{}.metaspace_utilization", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "MU: metaspace utilization"));
    metadata.insert("CCSC".to_string(),
        Metadata::new(format!("{}.compressed_class_space_capacity", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "CCSC: Compressed class space capacity"));
    metadata.insert("CCSU".to_string(),
        Metadata::new(format!("{}.compressed_class_space_used", METRIC_NAME_GC),
                      Rate::Gauge,
                      "kB",
                      "CCSU: Compressed class space used"));
    metadata.insert("YGC".to_string(),
        Metadata::new(format!("{}.young_generation_gc_events", METRIC_NAME_GC),
                      Rate::Counter,
                      "Event",
                      "YGC: Number of young generation garbage collection events"));
    metadata.insert("YGCT".to_string(),
        Metadata::new(format!("{}.young_generation_gc_time", METRIC_NAME_GC),
                      Rate::Counter,
                      "s",
                      "YGCT: Young generation garbage collection time"));
    metadata.insert("FGC".to_string(),
        Metadata::new(format!("{}.full_gc_events", METRIC_NAME_GC),
                      Rate::Counter,
                      "Event",
                      "FGC: Number of full GC events."));
    metadata.insert("FGCT".to_string(),
        Metadata::new(format!("{}.full_gc_time", METRIC_NAME_GC),
                      Rate::Counter,
                      "s",
                      "FGCT: Full garbage collection time"));
    metadata.insert("GCT".to_string(),
        Metadata::new(format!("{}.total_gc_time", METRIC_NAME_GC),
                      Rate::Counter,
                      "s",
                      "GCT: Total garbage collection time"));

    metadata
}

fn handle_command_output(command: &str, result: IoResult<Output>) -> Result<Output, Error> {
    match result {
        Ok(output) => {
            if output.status.success() {
                debug!("Successfully found and run {}.", command);
                Ok(output)
            } else {
                let exit_code = output.status.code().map_or("<received signal>".to_string(), |i| format!("{}", i));
                let stdout = String::from_utf8_lossy(&output.stdout);
                let stderr = String::from_utf8_lossy(&output.stderr);
                let msg = format!("Running {} returned exit code {}: out '{}', err '{}'.", command, exit_code, stdout, stderr);
                debug!("{}", msg);
                Err(Error::InitError(msg))
            }
        },
        Err(err) => {
            let msg = format!("Failed to run {}, because '{}'.", command, err.description());
            debug!("{}", msg);
            Err(Error::InitError(msg))
        },
    }
}

#[derive(Debug)]
struct JvmProcess {
    pid: u16,
    class: String,
    cmdline: String,
}

fn get_jps() -> Result<Vec<JvmProcess>, Error>{
    let result = execute_jps();
    let output = try!(handle_command_output("jps", result));
    let stdout = String::from_utf8_lossy(&output.stdout);
    let lines: Vec<&str> = stdout.lines().collect();
    if lines.is_empty() {
        let msg = format!("Failed to parse jps output");
        trace!("Failed to parse jps output for lines: '{}'", stdout);
        return Err(Error::CollectionError(msg));
    }

    let mut jps = Vec::new();
    for line in lines {
        let cols: Vec<&str> = line.split_whitespace().collect();
        if cols.len() < 2 {
            let msg = format!("Failed to parse jps output; expected 'PID CLASS CMDLINE'");
            trace!("Failed to parse jps output for lines: '{}'", stdout);
            return Err(Error::CollectionError(msg));
        }
        let pid: u16 = try!(cols[0].parse::<u16>());
        let jp = JvmProcess { pid: pid, class: cols[1].to_string(), cmdline: cols[2..].join(" ").to_string() };
        trace!("Found JVM Process '{:?}'", jp);
        jps.push(jp)
    }
    Ok(jps)
}

fn execute_jps() -> IoResult<Output> {
    // TODO: use timeout for execution
    Command::new("/usr/bin/jps").arg("-vl").output()
}

#[derive(Debug)]
struct IdentifiedJvm {
    pid: u16,
    name: Option<String>,
}

fn identify_jvms(jvm_configs: &Vec<JvmConfig>, jp: &JvmProcess) -> IdentifiedJvm {
    let mut name = None;
    for jvm_config in jvm_configs {
        if let Ok(re) = Regex::new(&jvm_config.Command) {
            if re.is_match(&jp.class) || re.is_match(&jp.cmdline) {
                name = Some(jvm_config.Name.clone());
                break;
            } else {
                warn!("Invalid regular express for '{:?}'", jvm_config);
            }
        }
    }
    IdentifiedJvm {pid: jp.pid, name: name }
}

#[derive(Debug)]
struct GcStat {
    jvm_name: String,
    name: String,
    value: f64,
}

fn sample_gc_stats(jvm: &IdentifiedJvm) -> Result<Vec<GcStat>, Error> {
    let result = execute_jstat(jvm);
    let output = try!(handle_command_output("jstat", result));
    let stdout = String::from_utf8_lossy(&output.stdout);
    let lines: Vec<&str> = stdout.lines().collect();
    if lines.len() != 2  {
        let msg = format!("Failed to parse jstat output for pid {}", jvm.pid);
        trace!("Failed to parse jstat out for lines: '{}'", stdout);
        return Err(Error::CollectionError(msg));
    }
    let names: Vec<&str> = lines[0].split_whitespace().collect();
    let values: Vec<&str> = lines[1].split_whitespace().collect();

    let mut gcstats = Vec::new();
    for i in 0..values.len() {
        let name = names[i];
        let value = try!(values[i].parse::<f64>());
        // Unwrap is safe, but only due to the filter in the main algorithm
        let gcstat = GcStat{ jvm_name: jvm.name.as_ref().unwrap().clone(), name: name.to_string(), value: value };
        trace!("Successfully run gcstat for JVM Process '{:?}': '{:?}'", jvm, gcstat);
        gcstats.push(gcstat);
    }

    Ok(gcstats)
}

fn execute_jstat(jvm: &IdentifiedJvm) -> IoResult<Output> {
    // TODO: use timeout for execution
    let pid = format!("{}", jvm.pid);
    Command::new("/usr/bin/jstat").arg("-gc").arg(pid).output()
}

fn gcstat_to_sample(metadata: &HashMap<String, Metadata>, gcstat: GcStat) -> Option<Sample> {
    let mut tags = Tags::new();
    tags.insert("jvm_name".to_string(), gcstat.jvm_name );
    let metric_name = metadata.get(&gcstat.name).map(|m| m.metric.to_string());
    if let Some(name) = metric_name {
        let sample = Sample::new_with_tags(name, gcstat.value, tags);
        Some(sample)
    } else {
        None
    }
}

<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![feature(globs)]

extern crate router = "route_recognizer";
extern crate conduit;

use std::collections::HashMap;
use std::any::{Any, AnyRefExt};
use std::fmt::Show;

use router::{Router, Match};
use conduit::{Method, Handler, Request, Response};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<Handler>>>
}

macro_rules! method_map(
    ($method:ident => $variant:ty) => (
        pub fn $method<'a, H: 'static + Handler>(&'a mut self, pattern: &str, handler: H)
                                                -> &'a mut RouteBuilder
        {
            self.map(conduit::$variant, pattern, handler)
        }
    )
)

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method, path: &str) -> Result<Match<&'a Box<Handler>>, String> {
        match self.routers.find(method) {
            None => Err(format!("No router found for {}", method)),
            Some(router) => router.recognize(path)
        }
    }

    pub fn map<'a, H: 'static + Handler>(&'a mut self,
                                        method: Method, pattern: &str, handler: H)
                                        -> &'a mut RouteBuilder
    {
        {
            let router = self.routers.find_or_insert_with(method, |_| Router::new());
            router.add(pattern, box handler as Box<Handler>);
        }
        self
    }

    pub fn get<'a, H: 'static + Handler>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder
    {
        self.map(conduit::Get, pattern, handler)
    }

    pub fn post<'a, H: 'static + Handler>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder
    {
        self.map(conduit::Post, pattern, handler)
    }

    pub fn put<'a, H: 'static + Handler>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder
    {
        self.map(conduit::Put, pattern, handler)
    }

    pub fn delete<'a, H: 'static + Handler>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder
    {
        self.map(conduit::Delete, pattern, handler)
    }

    pub fn head<'a, H: 'static + Handler>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder
    {
        self.map(conduit::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        let m = {
            let method = request.method();
            let path = request.path();

            self.recognize(&method, path).unwrap()
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert("router.params", box m.params.clone() as Box<Any>);
        }

        (*m.handler).call(request)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a mut Request) -> &'a router::Params {
    req.extensions().find(&"router.params")
        .and_then(|a| a.as_ref::<router::Params>())
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a mut Request {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

//impl<T: Request> RequestParams for T {}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::io::net::ip::IpAddr;
    use std::collections::HashMap;
    use std::io::MemReader;
    use super::*;

    use conduit;
    use conduit::{Handler, Method, Scheme, Host, Headers, Extensions};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_str(),
                extensions: HashMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn as_conduit_handler() {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", handler1);
        router.get("/posts/:id", handler1);

        let mut req = RequestSentinel::new(conduit::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_str().unwrap(), "1, Get".to_str());

        let mut req = RequestSentinel::new(conduit::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_str().unwrap(), "10, Post".to_str());
    }

    fn handler1(req: &mut conduit::Request) -> Result<conduit::Response, ()> {
        let mut res = vec!();
        res.push(req.params()["id"]);
        res.push(format!("{}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(res.connect(", ").into_bytes())
        })
    }
}
<commit_msg>Store the 'static Handler<commit_after>#![feature(macro_rules)]
#![feature(globs)]

extern crate router = "route_recognizer";
extern crate conduit;

use std::collections::HashMap;
use std::any::{Any, AnyRefExt};
use std::fmt::Show;

use router::{Router, Match};
use conduit::{Method, Handler, Request, Response};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<Handler + 'static>>>
}

macro_rules! method_map(
    ($method:ident => $variant:ty) => (
        pub fn $method<'a, H: 'static + Handler>(&'a mut self, pattern: &str, handler: H)
                                                -> &'a mut RouteBuilder
        {
            self.map(conduit::$variant, pattern, handler)
        }
    )
)

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method,
                         path: &str) -> Result<Match<&'a Box<Handler + 'static>>, String> {
        match self.routers.find(method) {
            None => Err(format!("No router found for {}", method)),
            Some(router) => router.recognize(path)
        }
    }

    pub fn map<'a, H: 'static + Handler>(&'a mut self,
                                        method: Method, pattern: &str, handler: H)
                                        -> &'a mut RouteBuilder
    {
        {
            let router = self.routers.find_or_insert_with(method, |_| Router::new());
            router.add(pattern, box handler as Box<Handler + 'static>);
        }
        self
    }

    pub fn get<'a, H: 'static + Handler>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder
    {
        self.map(conduit::Get, pattern, handler)
    }

    pub fn post<'a, H: 'static + Handler>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder
    {
        self.map(conduit::Post, pattern, handler)
    }

    pub fn put<'a, H: 'static + Handler>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder
    {
        self.map(conduit::Put, pattern, handler)
    }

    pub fn delete<'a, H: 'static + Handler>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder
    {
        self.map(conduit::Delete, pattern, handler)
    }

    pub fn head<'a, H: 'static + Handler>(&'a mut self, pattern: &str, handler: H)
                                            -> &'a mut RouteBuilder
    {
        self.map(conduit::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        let m = {
            let method = request.method();
            let path = request.path();

            self.recognize(&method, path).unwrap()
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert("router.params", box m.params.clone() as Box<Any>);
        }

        (*m.handler).call(request)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a mut Request) -> &'a router::Params {
    req.extensions().find(&"router.params")
        .and_then(|a| a.as_ref::<router::Params>())
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a mut Request {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

//impl<T: Request> RequestParams for T {}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::io::net::ip::IpAddr;
    use std::collections::HashMap;
    use std::io::MemReader;
    use super::*;

    use conduit;
    use conduit::{Handler, Method, Scheme, Host, Headers, Extensions};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_str(),
                extensions: HashMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn as_conduit_handler() {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", handler1);
        router.get("/posts/:id", handler1);

        let mut req = RequestSentinel::new(conduit::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_str().unwrap(), "1, Get".to_str());

        let mut req = RequestSentinel::new(conduit::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_str().unwrap(), "10, Post".to_str());
    }

    fn handler1(req: &mut conduit::Request) -> Result<conduit::Response, ()> {
        let mut res = vec!();
        res.push(req.params()["id"]);
        res.push(format!("{}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(res.connect(", ").into_bytes())
        })
    }
}
<|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();}

/// 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}
<commit_msg>Fix `slurp` to compile.<commit_after>#![feature(libc)]
extern crate libc;

use std::fs;
use std::io::Read;
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.
pub 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>#![feature(test)]

// The benchmarks here verify that the complexity grows as O(*n*)
// where *n* is the size of the text to be wrapped.

extern crate test;
extern crate hyphenation;
extern crate textwrap;

use test::Bencher;
use hyphenation::Language;
use textwrap::Wrapper;

fn lorem_ipsum(length: usize) -> &'static str {
    let text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas feugiat non mi \
                rutrum consectetur. Nulla iaculis luctus ex suscipit posuere. Sed et tellus quis \
                elit volutpat pretium. Sed faucibus purus vitae feugiat tincidunt. Nulla \
                malesuada interdum tempus. Proin consectetur malesuada magna, id suscipit enim \
                tempus in. Sed sollicitudin velit tortor, quis condimentum nisl vulputate \
                lobortis. Curabitur id lectus arcu. Nullam quis aliquam nisi. Vestibulum quam \
                enim, elementum vel urna scelerisque, ultricies cursus urna. Mauris vestibulum, \
                augue non posuere viverra, risus tortor iaculis augue, eget convallis metus nisl \
                vestibulum nisi. Aenean auctor dui vel aliquet sagittis. Aliquam quis enim \
                mauris. Nunc eu leo et orci euismod bibendum vel eu tortor. Nam egestas volutpat \
                ex, a turpis duis.";
    text.split_at(length).0
}

#[bench]
fn lorem_100(b: &mut Bencher) {
    let text = lorem_ipsum(100);
    b.iter(|| textwrap::fill(text, 60))
}

#[bench]
fn lorem_200(b: &mut Bencher) {
    let text = lorem_ipsum(200);
    b.iter(|| textwrap::fill(text, 60))
}

#[bench]
fn lorem_400(b: &mut Bencher) {
    let text = lorem_ipsum(400);
    b.iter(|| textwrap::fill(text, 60))
}

#[bench]
fn lorem_800(b: &mut Bencher) {
    let text = lorem_ipsum(800);
    b.iter(|| textwrap::fill(text, 60))
}

#[bench]
fn hyphenation_lorem_100(b: &mut Bencher) {
    let text = lorem_ipsum(100);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let mut wrapper = Wrapper::new(60);
    wrapper.corpus = Some(&corpus);

    b.iter(|| wrapper.fill(text))
}

#[bench]
fn hyphenation_lorem_200(b: &mut Bencher) {
    let text = lorem_ipsum(200);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let mut wrapper = Wrapper::new(60);
    wrapper.corpus = Some(&corpus);

    b.iter(|| wrapper.fill(text))
}

#[bench]
fn hyphenation_lorem_400(b: &mut Bencher) {
    let text = lorem_ipsum(400);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let mut wrapper = Wrapper::new(60);
    wrapper.corpus = Some(&corpus);

    b.iter(|| wrapper.fill(text))
}

#[bench]
fn hyphenation_lorem_800(b: &mut Bencher) {
    let text = lorem_ipsum(800);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let mut wrapper = Wrapper::new(60);
    wrapper.corpus = Some(&corpus);

    b.iter(|| wrapper.fill(text))
}
<commit_msg>benches: use a constant for the line length<commit_after>#![feature(test)]

// The benchmarks here verify that the complexity grows as O(*n*)
// where *n* is the size of the text to be wrapped.

extern crate test;
extern crate hyphenation;
extern crate textwrap;

use test::Bencher;
use hyphenation::Language;
use textwrap::Wrapper;

const LINE_LENGTH: usize = 60;

fn lorem_ipsum(length: usize) -> &'static str {
    let text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas feugiat non mi \
                rutrum consectetur. Nulla iaculis luctus ex suscipit posuere. Sed et tellus quis \
                elit volutpat pretium. Sed faucibus purus vitae feugiat tincidunt. Nulla \
                malesuada interdum tempus. Proin consectetur malesuada magna, id suscipit enim \
                tempus in. Sed sollicitudin velit tortor, quis condimentum nisl vulputate \
                lobortis. Curabitur id lectus arcu. Nullam quis aliquam nisi. Vestibulum quam \
                enim, elementum vel urna scelerisque, ultricies cursus urna. Mauris vestibulum, \
                augue non posuere viverra, risus tortor iaculis augue, eget convallis metus nisl \
                vestibulum nisi. Aenean auctor dui vel aliquet sagittis. Aliquam quis enim \
                mauris. Nunc eu leo et orci euismod bibendum vel eu tortor. Nam egestas volutpat \
                ex, a turpis duis.";
    text.split_at(length).0
}

#[bench]
fn lorem_100(b: &mut Bencher) {
    let text = lorem_ipsum(100);
    b.iter(|| textwrap::fill(text, LINE_LENGTH))
}

#[bench]
fn lorem_200(b: &mut Bencher) {
    let text = lorem_ipsum(200);
    b.iter(|| textwrap::fill(text, LINE_LENGTH))
}

#[bench]
fn lorem_400(b: &mut Bencher) {
    let text = lorem_ipsum(400);
    b.iter(|| textwrap::fill(text, LINE_LENGTH))
}

#[bench]
fn lorem_800(b: &mut Bencher) {
    let text = lorem_ipsum(800);
    b.iter(|| textwrap::fill(text, LINE_LENGTH))
}

#[bench]
fn hyphenation_lorem_100(b: &mut Bencher) {
    let text = lorem_ipsum(100);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let mut wrapper = Wrapper::new(LINE_LENGTH);
    wrapper.corpus = Some(&corpus);

    b.iter(|| wrapper.fill(text))
}

#[bench]
fn hyphenation_lorem_200(b: &mut Bencher) {
    let text = lorem_ipsum(200);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let mut wrapper = Wrapper::new(LINE_LENGTH);
    wrapper.corpus = Some(&corpus);

    b.iter(|| wrapper.fill(text))
}

#[bench]
fn hyphenation_lorem_400(b: &mut Bencher) {
    let text = lorem_ipsum(400);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let mut wrapper = Wrapper::new(LINE_LENGTH);
    wrapper.corpus = Some(&corpus);

    b.iter(|| wrapper.fill(text))
}

#[bench]
fn hyphenation_lorem_800(b: &mut Bencher) {
    let text = lorem_ipsum(800);
    let corpus = hyphenation::load(Language::Latin).unwrap();
    let mut wrapper = Wrapper::new(LINE_LENGTH);
    wrapper.corpus = Some(&corpus);

    b.iter(|| wrapper.fill(text))
}
<|endoftext|>